home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
MACD 5
/
MACD 5.bin
/
workbench
/
wb
/
czesc_1
/
cgwbpattern101
/
ilbmtoppm.lha
/
src
/
libfloyd.c
< prev
next >
Wrap
C/C++ Source or Header
|
1994-10-25
|
7KB
|
241 lines
/* libfloyd.c - generic Floyd-Steinberg error distribution routines for PBMPlus
**
** Copyright (C) 1994 Ingo Wilken (Ingo.Wilken@informatik.uni-oldenburg.de)
**
** Permission to use, copy, modify, and distribute this software and its
** documentation for any purpose and without fee is hereby granted, provided
** that the above copyright notice appear in all copies and that both that
** copyright notice and this permission notice appear in supporting
** documentation. This software is provided "as is" without express or
** implied warranty.
*/
#include "ppmfloyd.h"
static void fs_adjust ARGS((ppm_fs_info *fi, int col));
ppm_fs_info *
#if __STDC__
ppm_fs_init(int cols, pixval maxval, int flags)
#else
ppm_fs_init(cols, maxval, flags)
int cols;
pixval maxval;
int flags;
#endif
{
ppm_fs_info *fi;
int i;
if( (fi = (ppm_fs_info *)malloc(sizeof(ppm_fs_info))) &&
(fi->thisrederr = (long *)malloc((cols+2) * sizeof(long))) &&
(fi->thisgreenerr = (long *)malloc((cols+2) * sizeof(long))) &&
(fi->thisblueerr = (long *)malloc((cols+2) * sizeof(long))) &&
(fi->nextrederr = (long *)malloc((cols+2) * sizeof(long))) &&
(fi->nextgreenerr = (long *)malloc((cols+2) * sizeof(long))) &&
(fi->nextblueerr = (long *)malloc((cols+2) * sizeof(long))) ) {
fi->lefttoright = 1;
fi->cols = cols;
fi->maxval = maxval;
fi->flags = flags;
if( flags & FS_RANDOMINIT ) {
srandom((int)(time(0) ^ getpid()));
for( i = 0; i < cols +2; i++ ) {
/* random errors in [-1..+1] */
fi->thisrederr[i] = random() % 32 - 16;
fi->thisgreenerr[i] = random() % 32 - 16;
fi->thisblueerr[i] = random() % 32 - 16;
}
}
else {
for( i = 0; i < cols + 2; i++ )
fi->thisrederr[i] = fi->thisgreenerr[i] = fi->thisblueerr[i] = 0;
}
return fi;
}
pm_error("out of memory allocating Floyd-Steinberg control structure");
}
void
ppm_fs_free(fi)
ppm_fs_info *fi;
{
if( fi ) {
free(fi->thisrederr); free(fi->thisgreenerr); free(fi->thisblueerr);
free(fi->nextrederr); free(fi->nextgreenerr); free(fi->nextblueerr);
free(fi);
}
}
int
ppm_fs_startrow(fi, pixrow)
ppm_fs_info *fi;
pixel *pixrow;
{
register int col;
if( !fi )
return 0;
fi->pixrow = pixrow;
for( col = 0; col < fi->cols + 2; col++ )
fi->nextrederr[col] = fi->nextgreenerr[col] = fi->nextblueerr[col] = 0;
if( fi->lefttoright ) {
fi->col_end = fi->cols;
col = 0;
}
else {
fi->col_end = -1;
col = fi->cols - 1;
}
fs_adjust(fi, col);
return col;
}
int
ppm_fs_next(fi, col)
ppm_fs_info *fi;
int col;
{
if( !fi )
++col;
else {
if( fi->lefttoright )
++col;
else
--col;
if( col == fi->col_end )
col = fi->cols;
else
fs_adjust(fi, col);
}
return col;
}
void
ppm_fs_endrow(fi)
ppm_fs_info *fi;
{
long *tmp;
if( fi ) {
tmp = fi->thisrederr; fi->thisrederr = fi->nextrederr; fi->nextrederr = tmp;
tmp = fi->thisgreenerr; fi->thisgreenerr = fi->nextgreenerr; fi->nextgreenerr = tmp;
tmp = fi->thisblueerr; fi->thisblueerr = fi->nextblueerr; fi->nextblueerr = tmp;
if( fi->flags & FS_ALTERNATE )
fi->lefttoright = !(fi->lefttoright);
}
}
void
ppm_fs_update(fi, col, pP)
ppm_fs_info *fi;
int col;
pixel *pP;
{
if( fi )
ppm_fs_update3(fi, col, PPM_GETR(*pP), PPM_GETG(*pP), PPM_GETB(*pP));
}
void
#if __STDC__
ppm_fs_update3(ppm_fs_info *fi, int col, pixval r, pixval g, pixval b)
#else
ppm_fs_update3(fi, col, r, g, b)
ppm_fs_info *fs;
int col;
pixval r, g, b;
#endif
{
register long rerr, gerr, berr, err;
int errcol = col+1;
if( !fi )
return;
rerr = (long)(fi->red) - r;
gerr = (long)(fi->green) - g;
berr = (long)(fi->blue) - b;
if( fi->lefttoright ) {
register long two_err;
two_err = 2*rerr;
err = rerr; fi->nextrederr[errcol+1] += err; /* 1/16 */
err += two_err; fi->nextrederr[errcol-1] += err; /* 3/16 */
err += two_err; fi->nextrederr[errcol ] += err; /* 5/16 */
err += two_err; fi->thisrederr[errcol+1] += err; /* 7/16 */
two_err = 2*gerr;
err = gerr; fi->nextgreenerr[errcol+1] += err; /* 1/16 */
err += two_err; fi->nextgreenerr[errcol-1] += err; /* 3/16 */
err += two_err; fi->nextgreenerr[errcol ] += err; /* 5/16 */
err += two_err; fi->thisgreenerr[errcol+1] += err; /* 7/16 */
two_err = 2*berr;
err = berr; fi->nextblueerr[errcol+1] += err; /* 1/16 */
err += two_err; fi->nextblueerr[errcol-1] += err; /* 3/16 */
err += two_err; fi->nextblueerr[errcol ] += err; /* 5/16 */
err += two_err; fi->thisblueerr[errcol+1] += err; /* 7/16 */
}
else {
register long two_err;
two_err = 2*rerr;
err = rerr; fi->nextrederr[errcol-1] += err; /* 1/16 */
err += two_err; fi->nextrederr[errcol+1] += err; /* 3/16 */
err += two_err; fi->nextrederr[errcol ] += err; /* 5/16 */
err += two_err; fi->thisrederr[errcol-1] += err; /* 7/16 */
two_err = 2*gerr;
err = gerr; fi->nextgreenerr[errcol-1] += err; /* 1/16 */
err += two_err; fi->nextgreenerr[errcol+1] += err; /* 3/16 */
err += two_err; fi->nextgreenerr[errcol ] += err; /* 5/16 */
err += two_err; fi->thisgreenerr[errcol-1] += err; /* 7/16 */
two_err = 2*berr;
err = berr; fi->nextblueerr[errcol-1] += err; /* 1/16 */
err += two_err; fi->nextblueerr[errcol+1] += err; /* 3/16 */
err += two_err; fi->nextblueerr[errcol ] += err; /* 5/16 */
err += two_err; fi->thisblueerr[errcol-1] += err; /* 7/16 */
}
}
static void
fs_adjust(fi, col)
ppm_fs_info *fi;
int col;
{
register long r, g, b;
register pixel *pP;
int errcol = col+1;
pixval maxval = fi->maxval;
pP = &(fi->pixrow[col]);
/* Use Floyd-Steinberg errors to adjust actual color. */
r = fi->thisrederr [errcol]; if( r < 0 ) r -= 8; else r += 8; r /= 16;
g = fi->thisgreenerr[errcol]; if( g < 0 ) g -= 8; else g += 8; g /= 16;
b = fi->thisblueerr [errcol]; if( b < 0 ) b -= 8; else b += 8; b /= 16;
r += PPM_GETR(*pP); if ( r < 0 ) r = 0; else if ( r > maxval ) r = maxval;
g += PPM_GETG(*pP); if ( g < 0 ) g = 0; else if ( g > maxval ) g = maxval;
b += PPM_GETB(*pP); if ( b < 0 ) b = 0; else if ( b > maxval ) b = maxval;
PPM_ASSIGN(*pP, r, g, b);
fi->red = r; fi->green = g; fi->blue = b;
}